#ifndef INC_NAMESERVER_H_
#define INC_NAMESERVER_H_

#include <Poco/Runnable.h>
#include <Poco/Thread.h>
#include <Poco/Mutex.h>
#include <string>
#include <map>
#include "misc/UDPNet.h"
#include "misc/MultiNet.h"
#include "misc/Timer.h"
#include "nameserver/misc/Ring.h"
#include "nameserver/net/nsMsg.h"

#define PROCESS_EVENT "PROCESS"
#define QUIT_EVENT "QUIT"
#define MIN_PORT_RANGE_ 4000
#define MAX_PORT_RANGE_ 5000

#define ACK_MAP std::map<std::string, std::map<unsigned long, std::string> >
#define DISCONNECTED_MAP std::map<std::string, Poco::Timestamp>
#define KEEPALIVE_MAP std::map<std::string, Poco::Timestamp>
/*********************************************************/
class NameServer : public Poco::Runnable
{
private:
	// Friends
	friend class Discovery;
	friend class RingRequest;
	friend class Register;
	friend class RingDisconnect;
	friend class UnRegister;
	friend class Announce;
	friend class RingDeny;
	friend class RingReply;
	friend class KeepAlive;
	friend class nsMsg;
	friend class Ack;

	// Members
	mutable Poco::Mutex		mutex;		// Mutual exclusion object
	Poco::Thread			lThread;	// Thread handle
	Poco::Timestamp			refreshTime;	// refreshtime keeps track of how many seconds have passed since we last broadcasted our presence
	Poco::Timestamp			keepAliveCheck;	// Keeps track of the last time we checked our keep alive map
	static NameServer&		pInstance;	// Singleton instance
	std::vector<Ring>		rings;		// Vector storing all registered rings
	ACK_MAP				packets;	// Map keeping track of packets that are awaiting acknowledgement
	KEEPALIVE_MAP			keepalive;	// Map keeping track of the last instants of time we received a message from a node/client
	DISCONNECTED_MAP		disconnected;	// Keeps track of recently disconnected nodes, so we don't keep sending keepalive packets
	Timer*				clock;		// Clock frequently activates processing to check keepalive timers & broadcast the nameserver
	UDPNet*				unicast;	// Unicast class
	MultiNet*			multicast;	// Multicast class
	std::string			netInt;		// stores the used network interface for the sockets
	bool				quitFlag;	// Flags a quit to the thread
	unsigned long			counter;	// The job id counter

	// Methods
	void run();
	unsigned long getID();				// Returns a new unique id for a network packet
	void remove(const std::string&);		// Removes the keepalive & ack entries for the given node address
	void broadcastPresence();			// Sends a broadcast message every few seconds
	void processKeepAlive();			// Checks the keepalive timers & sends keepalive packets accordingly

	// Construction & Destruction
	NameServer() {counter = 0;};			// Constructor
	NameServer(const NameServer&) {};		// Copy constructor
	NameServer& operator=(const NameServer&);	// Assignment operator

public:
	// Methods
	void start();					// Start the Nameserver
	void wait();					// Wait for a quit event ( blocking call! )
	void stop();					// stop the nameserver

	// Network methods
	void send(const nsMsg*);			// Send a message to the stored response address
	void sendTo(const nsMsg*, const std::string&);	// Send a message to a specified address
	void broadcast(const nsMsg*);			// Broadcast a message on the multicast group
	std::string getLocalAddress() const;		// Returns the local address of the nameserver ( unicast )

	// Information retrieval
	std::string getActivity() const;		// Returns the an overview of the latest activity of all connected clients/nodes
	std::string getLoad() const;			// Returns a load overview for all known rings
	std::string getLoad(const std::string&) const;	// Returns a load overview for a specific ring

	// Construction & Destruction
	static NameServer& Instance();			// Singleton instance retrieval
	virtual ~NameServer() {};			// Destructor
};
/*********************************************************/
#endif //INC_NAMESERVER_H_
